<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-type" content="text/html; charset=utf-8">
	<title>Calculator Executor Test</title>

	<script type="text/javascript" src="../../../dojo/dojo.js" data-dojo-config="isDebug:true, parseOnLoad: true"></script>

	<script type="text/javascript">
		dojo.require("doh.runner");
		dojo.require("dojox.calc._Executor");
		dojo.require("dojo.number");

		var executor;
		var waitForLoad = new doh.Deferred();
		function executorLoaded(){
			executor = dijit.byId('executor');
			waitForLoad.callback(true);
		}
		function test(text, ans){
			if (ans!=true&&ans!=false)
				ans = dojox.calc.approx(ans);
			console.log("text is "+text);
			doh.is(ans, dojox.calc.approx(executor.eval(text)), text);
		}
		/*function approx(r){
			return Math.round(r * (1 << 30)) / (1 << 30);
		}*/
		var status = "Error(s) on page";
		dojo.addOnLoad(function(){
			function allTests(){
				dojo.byId("status").innerHTML = "Testing...";
				func = executor.Function("fcn1", "i,j","k=i+j+1;return k;");

				executor.Function("prompt", "", "	return (arguments[2]=='j') ? 6 : NaN	");
				test("fcn1(5)", 12);
				test(func(4), 11);
				executor.Function("fcn2", "i","return j=fcn1(k,i);");
				test("fcn2(i=fcn1(6,7))", 29);
				test("j+k", 58);

				// number conversion tests
				test("toRadix(5,2)", "0b101");
				test("toRadix(toRadix(5,2), 10)", 5);
				test("toRadix(toRadix(5,3), 10)", 5);
				test("toRadix(0xf, 16)", "0xf");

				test("toRadix(0xf, 15)", "10#15");
				test("toRadix(0b1111, 15)", "10#15");
				test("toRadix(0o17, 15)", "10#15");
				test("toRadix(10#15, 16)", "0xf");
				test("toRadix(10#15, 2)", "0b1111");
				test("toRadix(10#15, 8)", "0o17");

				test("toRadix(0xf, 10)", "15");
				test("toRadix(0xf, 2)", "0b1111");
				test("toRadix(0b1111, 16)", "0xf");
				test("toRadix(0o111, 16)", "0x49");
				
				// unary tests
				test("0--2", 2);
				test("0 --2", 2);
				test("0 - -2", 2);
				test("0 - - 2", 2);
				test("0- -2", 2);
				test("0- - 2", 2);
				test("0 -  -  2", 2);
				test("0  --2", 2);
				test("0  - - 2", 2);

				// pi tests
				// some browsers get 8105800789910702, some get 8105800789910700
				test("Math.abs(pi^32-8105800789910701) <= 1", true);
				test("32\u221A8105800789910700", Math.PI);
				test("64\u221A65704006445717084572022626334541", Math.PI);

				// new pow tests
				test(" (-27)^(1/3) ", -3);
				test(" (-36)^(1/2) ", NaN);

				test("y=true", true);
				test("y=!y", false);
				test("y=(true||!true)", true);
				test("x=5", 5);
				test("x", 5);
				test("x++", 5);
				test("x", 6);
						
				test("x--", 6);
				test("x", 5);
				test("x==5", true);
				test("5+x++", 10);

				test("x", 6);

				test("x=5", 5);
				test("y=(x!=6)", true);// x != 6
				test("x=3", 3);
				test("y=(x!!=6)", false);// factorial(x) != 6
				test("5", 5);
				test("3!", 6);
				test("\u221A(3!)", Math.sqrt(dojox.math.factorial(3))); // 2.4494897427831780981972840747059);
				// factorial goes first, 2^3! = 2^6
				test("\u221A3!", Math.sqrt(dojox.math.factorial(3))); // 2.4494897427831780981972840747059);
				test("\u221A(3!^2)", 6);
				test("3\u221A(3!^3)", 6);
				test("4\u221A(4^4)", 4);
				test("(4^(1/2))\u221A(4^2)", 4);
				test("(4^(1/2))\u221A4^2", 4);
				test("4^(1/2)\u221A(4^2)", 4);
				test("4^(1/2)\u221A4^2", 4);

				test("2^Math.sin(\u03C0)", 1);
				test("\u221A\u221A"+"16", 2);
				test("Math.sqrt(\u221A16, 2)", 2);
				test("\u221AMath.sqrt(16, 2)", 2);

				// New Radical tests
				test("\u221A2\u221A4\u221A16", 2);
				test("2\u221A4\u221A16", 4);
				test("2^2\u221A16", 2);
				test("2^-3^-4", Math.pow(2,(-Math.pow(3,(-4)))));
				test("2^-2\u221A4", .25);


				test("2^Math.sin((\u03C0))", 1);
				test("2^Math.sin(3!!)", dojox.calc.pow(2, Math.sin(dojox.math.factorial(dojox.math.factorial(3)))));
				test("2^Math.sin((3!)!)", dojox.calc.pow(2, Math.sin(dojox.math.factorial(dojox.math.factorial(3)))));
				test("2^Math.sin((3!+3!)-1)", dojox.calc.pow(2, Math.sin((dojox.math.factorial(3)+dojox.math.factorial(3))-1)));
				test("2^\u221A-Math.sin(3!+3!-1)", dojox.calc.pow(2, Math.sqrt(-Math.sin(dojox.math.factorial(3)+dojox.math.factorial(3)-1))));
				test("2^-\u221A+4", 1/4);
				test("2^-2\u221A+4", 1/4);
				test("2^(-2)\u221A+4", 256);
				test("2^2\u221A+4", Math.sqrt(2));
				test("2^\u221A+4", 4);
				test("2^-(-2)\u221A+4", dojox.calc.pow(2, (-1/2)));
				test("2^--2\u221A+4", 4);
				test("-\u221A4", -2);
				test("2^-2", 1/4);
				test("--2", 2);
				test("pow(2^2, 2^2)", 256)
				// extreme negative sign scenarios
				test("2^--\u221A--4", 4);
				test("---\u221A--4", -2);
				test("---\u221A4", -2);
				test("---2*(3-5)+1", 5);
				test("---(2*(3-5))+1", 5);
				// floating poMath.floor tests
				test("--4.56443*2", 4.56443*2);
				test("\u221A--\u221A4.56443*2", Math.sqrt(Math.sqrt(4.56443))*2);//2.923321855);
				test("\u221A--\u221A4.56443!*2", Math.sqrt(Math.sqrt(dojox.math.factorial(4.56443)))*2);
				test("--4.56443*2-4.56443", 4.56443);
				// more arithmetic
				test("4*2-(5+2*3-2)*6/-2", 35);
				test("Math.floor(2^3^4)+Math.floor(2^Math.floor(2))", 4100);
				// scientific notation
				test("10e10", 10e10);
				test("10e-10", 10e-10);
				test("10e+10", 10e10);
				test("10e+10*2", 10e10*2);
				test("2*10e+10*2", 2*10e10*2);
				test("2*10e10*2", 2*10e10*2);
				// with \u221A (radicals)
				test("\u221A10e10*2", Math.sqrt(10e10)*2);
				test("\u221A10e-10*2", Math.sqrt(10e-10)*2);
				test("5\u221A10e-10*2", dojox.calc.pow(10e-10, 1/5)*2);
				test("5\u221A10e-10*2+5\u221A10e-10*2", dojox.calc.pow(10e-10, 1/5)*2*2);

				test("2^3!\u221A3", dojox.calc.pow(3, 1/dojox.calc.pow(2, 6)));
				test("2^-3!\u221A3", dojox.calc.pow(2, -dojox.calc.pow(3, 1/dojox.math.factorial(3))));
				test("2^(-3!)\u221A3", dojox.calc.pow(3, 1/dojox.calc.pow(2, -dojox.math.factorial(3))));

				// full space tests
				test(" x = 5 ", 5);
				test(" x ", 5);
				test(" x ++ ", 5);
				test(" x ", 6);
				test(" x -- ", 6);
				test(" x ", 5);
				test(" x == 5 ", true);
				test(" 5 ", 5);
				test(" 3 !", 6);
				test(" \u221A ( 3 ! )", Math.sqrt(dojox.math.factorial(3))); //2.4494897427831780981972840747059);
				// factorial goes first, 2^3! = 2^6
				test(" \u221A 3 !", Math.sqrt(dojox.math.factorial(3))); //2.4494897427831780981972840747059);
				test(" \u221A ( 3 ! ^ 2 ) ", 6);
				test(" 3 \u221A ( 3 ! ^ 3 ) ", 6);
				test(" 4 \u221A ( 4 ^ 4 ) ", 4);
				test(" ( 4 ^ ( 1 / 2 ) ) \u221A ( 4 ^ 2 ) ", 4);
				test(" ( 4 ^ ( 1 / 2 ) ) \u221A 4 ^ 2 ", 4);
				test(" 4 ^ ( 1 / 2 ) \u221A ( 4 ^ 2 ) ", 4);
				test(" 4 ^ ( 1 / 2 ) \u221A 4 ^ 2 ", 4);

				test(" 2 ^ Math.sin ( \u03C0 ) ", 1);
				test(" \u221A \u221A 16 ", 2);
				test(" Math.sqrt ( \u221A 16 , 2 )", 2);
				test(" \u221A Math.sqrt ( 16 , 2 ) ", 2);

				test(" 2 ^ Math.sin ( ( \u03C0 ) ) ", 1);
				test(" 2 ^ Math.sin ( 3 ! ! ) ", dojox.calc.pow(2, Math.sin(dojox.math.factorial(dojox.math.factorial(3)))));
				test(" 2 ^ Math.sin( ( 3 ! ) ! ) ", dojox.calc.pow(2, Math.sin(dojox.math.factorial(dojox.math.factorial(3)))));
				test(" 2 ^ Math.sin ( ( 3 ! + 3 ! ) - 1 ) ", dojox.calc.pow(2, Math.sin((dojox.math.factorial(3)+dojox.math.factorial(3))-1)));
				test(" 2 ^ \u221A - Math.sin ( 3 ! + 3 ! - 1 ) ", dojox.calc.pow(2, Math.sqrt(-Math.sin(dojox.math.factorial(3)+dojox.math.factorial(3)-1))));
				test(" 2 ^ - \u221A + 4 ", 1/4);
				test(" 2 ^ - 2 \u221A + 4 ", 1/4);
				test(" 2 ^ ( - 2 ) \u221A + 4 ", 256);
				test(" 2 ^ 2 \u221A + 4 ", Math.sqrt(2));
				test(" 2 ^ \u221A + 4 ", 4);
				test(" 2 ^ - ( - 2 ) \u221A + 4 ", dojox.calc.pow(2, (-1/2)));
				test(" 2 ^ - - 2 \u221A + 4 ", 4);
				test(" - \u221A 4 " , -2);
				test(" 2 ^ - 2 ", 1/4);
				test(" - - 2 ", 2);
				test("pow( 2 ^ 2 ,  2 ^ 2)", 256)

				// extreme negative sign scenarios
				test(" 2 ^ - - \u221A - - 4 ", 4);
				test(" - - - \u221A - - 4 ", -2);
				test(" - - - \u221A 4 ", -2);
				test(" - - - 2 * ( 3 - 5 ) + 1 ", 5);
				test(" - - - ( 2 * ( 3 - 5 ) ) + 1 ", 5);
				// floating point tests
				test(" - - 4.56443 * 2 ", 4.56443*2);
				test(" \u221A - - \u221A 4.56443 * 2 ", Math.sqrt(Math.sqrt(4.56443))*2);
				test(" \u221A - - \u221A 4.56443 ! * 2 ", Math.sqrt(Math.sqrt(dojox.math.factorial(4.56443)))*2);
				test(" - - 4.56443 * 2 - 4.56443 ", 4.56443);
				// more arithmetic
				test(" 4 * 2 - ( 5 + 2 * 3 - 2 ) * 6 / - 2 ", 35);
				test("Math.floor( 2 ^ 3 ^ 4 )+Math.floor( 2 ^ Math.floor ( 2 ) ) ", 4100);
				// scientific notation
				test(" 2 * 10e+10 * 2 ", 2*10e10*2);
				test(" 2 * 10e10 * 2 ", 2*10e10*2);
				// with \u221A (radicals)
				test(" \u221A 10e10 * 2 ", Math.sqrt(10e10)*2);
				test(" \u221A 10e-10 * 2 ", Math.sqrt(10e-10)*2);
				test(" 5 \u221A 10e-10 * 2 ", dojox.calc.pow(10e-10, 1/5)*2);
				test(" 5 \u221A 10e-10 * 2 + 5 \u221A 10e-10 * 2 ", dojox.calc.pow(10e-10, 1/5)*2*2);

				test(" 2 ^ 3 ! \u221A 3 ", dojox.calc.pow(3, 1/dojox.calc.pow(2, 6)));
				test(" 2 ^ - 3 ! \u221A 3 ", dojox.calc.pow(2, -dojox.calc.pow(3, 1/dojox.math.factorial(3))));
				test(" 2 ^ ( - 3 ! ) \u221A 3 ", dojox.calc.pow(3, 1/dojox.calc.pow(2, -dojox.math.factorial(3))));

				test("3!=6", true);
				test("3!==6", true);

				// try to break it on purpose; once upon a time, some might have caused infinite loops
				test("2*2.4.5", NaN);

				test("2^^3", NaN);
				test("2^^^^^^3", NaN);
				test("2^^^^^^^3", NaN);
				test("^2^3", NaN);
				test("!2^3", false);
				test("!2!+3!", 6);
				test("2+3\u221A", NaN);
				test("2+3\u221A^", NaN);
				test("!", NaN);
				test("((23+4)", NaN);					
				test("4+", NaN);
				test("4++", NaN);

				status = "Completed without errors";
			}
			doh.register("dojox.calc._Executor", [
				{
					name: "wait for Executor to load",
					timeout: 5000,
					runTest: function(){ if(!executor){ return waitForLoad; }}
				},
				{
					name: "Executor tests",
					timeout: 9000,
					runTest: function(){ allTests() }

				},
				function done(){
				       	dojo.byId("status").innerHTML = status;
				}
			]);
			doh.run();
		});
	</script>
</head>
<body>
	<b>dojox.calc._Executor tests</b>
	<div id="status" style="direction:ltr">Loading...</div>
	<span id="executor" data-dojo-type="dojox.calc._Executor" data-dojo-props='onLoad:function(){ executorLoaded() }'></span>
</body>
</html>
